#!/usr/bin/env python
# $Id: ping.py fc65281b178f 2012/12/22 08:44:41 pgurumur $
# Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# File ping.py generated on Sunday December 09, 2012 @00:34:40 PST
#
__version__  = "$Revision: fc65281b178f $"
__author__   = "$Author: pgurumur $"
__modified__ = "$Date: 2012-12-22 08:44:41Z $"

import optparse
import os
import struct
import socket
import sys

from venya.lib import cmdparser, exception, ip, stdlib

class pinger(cmdparser.GetOpt):
   option_list = (
         optparse.make_option("-4", "--ipv4", action = "store_true",
            help = "Traceroute to IPv4 address", default = False, dest = "v4"),
         optparse.make_option("-6", "--ipv6", action = "store_true",
            help = "Traceroute to IPv6 address", default = False, dest = "v6"),
         optparse.make_option("-c", "--count", type = "int",
            help = "Number of packets to send icmp echo request",
            default = 0, dest = "count"),
         optparse.make_option("-s", "--size", type = "int",
            help = "Packet size, default = 58", default = 58,
            dest = "size"),
         optparse.make_option("-t", "--ttl", type = "int",
            help = "TTL value", default = 255, dest = "ttl"),
         optparse.make_option("-n", "--numeric", action = "store_true",
            help = "Numeric output only", default = False, dest = "numeric"),
   ) + cmdparser.GetOpt.option_list

   usage = "[ options ] host(s)"

   help = """

   More details to come, after working on ping

   """

   def __init__(self, **kwargs):
      super(pinger, self).__init__(**kwargs)
      self._family = -1
      self._socket = 0
      self._dns = True
      self._sock = None
      self._maxDupCheck = 8 * 8192
      self._ident = os.getpid() & 0xFFFF
      self._echo = 8

   @property
   def version(self):
      retval = 0
      if self._family == socket.AF_INET:
         retval = 4
      elif self._family == socket.AF_INET6:
         retval = 6

      return retval

   def checksum(self, source):
      nleft = len(source)
      accum = 0
      flag = True
      count = 0
      while flag:
         try:
            accum += ord(source[count + 1])
            count += 2
            if count > nleft:
               flag = False
         except IndexError:
            flag = False

      count = nleft - count
      accum = (accum >> 16) + (accum & 0xFFFF)
      accum += (accum >> 16)
      accum = (accum & 0xFFFF) >> 8 | (accum << 8 & 0xFF00)
      print(accum)
      return accum

   def _icmpsocket(self):
      protocol = None
      if self.version == 4:
         protocol = "icmp"
      elif self.version == 6:
         protocol = "ipv6-icmp"

      try:
         self._sock = socket.socket(self._family, socket.SOCK_RAW,
               socket.getprotobyname(protocol))
         self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_DEBUG, 1)
         self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_DONTROUTE, 1) 
      except socket.error as err:
         self.error(err)

   def ping(self, host):
      if host and self._family:
         mesg = stdlib.sprintf("\nping%d to %s, pid: %d", self.version,
               host, os.getpid())
         self._icmpsocket()
         count = 1
         header = struct.pack(">bbHHH", self._echo, 0, 0, self._ident, count)
         data = 192 * 'Q'
         flag = True
         while flag:
            header = struct.pack(">bbHHH", self._echo, 0,
                  self.checksum(header + data), self._ident, count)
            packet = header + data
            sent = self._sock.sendto(packet, (host, 1))
            (data, self._addr) = self._sock.recvfrom(1024)
            print(self._addr)
            flag = False


   @cmdparser.getopts
   def handle(self):
      if self.options.v4 and self.options.v6:
         self.error("choose either IPv4 or IPv6, not both")

      hosts = []
      try:
         hosts = self.arguments[1:]
      except IndexError:
         self.error("Need hostnames to ping!")

      if os.geteuid() != 0:
         self.error("Need to run as root!")

      if self.options.numeric:
         self._dns = False

      if self.options.v4:
         self._family = socket.AF_INET
      elif self.options.v6:
         self._family = socket.AF_INET6

      if self._family == -1:
         self._family = socket.AF_INET

      for host in hosts:
         self.ping(host)

if __name__ == "__main__":
   ping = None
   try:
      ping = pinger(version = 0.1, args = sys.argv)
      if len(ping) <= 1:
         ping.printhelp()
      else:
         ping.handle()
   except exception.GetOptError as err:
      print(err)
      sys.exit(1)
